package com.airbat.prize.modules.system.controller.auth;

import cn.hutool.core.util.StrUtil;
import com.airbat.prize.common.enums.CommonStatusEnum;
import com.airbat.prize.common.pojo.CommonResult;
import com.airbat.prize.common.util.collection.SetUtils;
import com.airbat.prize.modules.system.controller.auth.vo.auth.*;
import com.airbat.prize.modules.system.convert.auth.SysAuthConvert;
import com.airbat.prize.modules.system.dal.dataobject.permission.SysMenuDO;
import com.airbat.prize.modules.system.dal.dataobject.permission.SysRoleDO;
import com.airbat.prize.modules.system.dal.dataobject.user.SysUserDO;
import com.airbat.prize.modules.system.dal.redis.common.SysCaptchaRedisDAO;
import com.airbat.prize.modules.system.enums.permission.MenuTypeEnum;
import com.airbat.prize.modules.system.framework.captcha.config.CaptchaProperties;
import com.airbat.prize.modules.system.service.auth.SysAuthService;
import com.airbat.prize.modules.system.service.permission.SysPermissionService;
import com.airbat.prize.modules.system.service.permission.SysRoleService;
import com.airbat.prize.modules.system.service.user.SysUserService;
import com.airbat.prize.operatelog.core.annotations.OperateLog;
import com.airbat.prize.web.web.config.LoginProperties;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

import static com.airbat.prize.common.pojo.CommonResult.error;
import static com.airbat.prize.common.pojo.CommonResult.success;
import static com.airbat.prize.common.util.servlet.ServletUtils.getClientIP;
import static com.airbat.prize.common.util.servlet.ServletUtils.getUserAgent;
import static com.airbat.prize.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.airbat.prize.security.core.util.SecurityFrameworkUtils.getLoginUserRoleIds;

//import com.airbat.prize.modules.system.framework.login.config.LoginProperties;

@Api(tags = "认证")
@RestController
@RequestMapping("/")
@Validated
@Slf4j
public class SysAuthController {

    @Resource
    private SysAuthService authService;
    @Resource
    private SysUserService userService;
    @Resource
    private SysRoleService roleService;
    @Resource
    private SysPermissionService permissionService;
    @Resource
    private CaptchaProperties captchaProperties;
    @Resource
    private SysCaptchaRedisDAO captchaRedisDAO;
    @Resource
    private LoginProperties loginProperties;
    @Resource
    private PasswordEncoder passwordEncoder;

    @PostMapping("/login")
    @ApiOperation("使用账号密码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
        SysUserDO user = userService.getUserByUsername(reqVO.getUsername());
        if (user == null) {
//            throw new UsernameNotFoundException(reqVO.getUsername());
            return error(reqVO.getUsername() + "不存在");
        }
        if (StringUtils.isNotEmpty(user.getWhiteIp()) && !user.getWhiteIp().contains(getClientIP()))
            return error("登录IP不符合不在白名单内");
        if (authService.checkLock(user.getUsername()) != null && authService.checkLock(user.getUsername()).equals("lock")) {
            Boolean zs = true;
            if (zs) {
                return error("该用户连续5次输入密码错误，已被锁定，请30分钟后重试");
            }
        }
        if (StringUtils.isNotEmpty(reqVO.getPassword())) {
            if (!passwordEncoder.matches(reqVO.getPassword(), user.getPassword())) {
                String lock = authService.checkLock(reqVO.getUsername());
                if (lock == null) {
                    authService.errorCount(reqVO.getUsername(), 1);
                    return error("登录失败，账号密码不正确,您还有4次机会");
                } else {
                    int times = Integer.parseInt(lock);
                    times++;
                    if (times < 5) {//错误次数加一
                        authService.errorCount(reqVO.getUsername(), times);
                        return error("登录失败，账号密码不正确，您还有" + (5 - times) + "次机会");
                    } else {//锁定
                        authService.lock(reqVO.getUsername());
                        return error("改用户连续5次输入密码错误，已被锁定，请30分钟后重试");
                    }
                }
            }
        }

        String token = authService.login(reqVO, getClientIP(), getUserAgent());
        // 返回结果
        return success(SysAuthLoginRespVO.builder().token(token).build());
    }

    @GetMapping("/network")
    @ApiOperation("获取当前网络环境")
    @OperateLog(enable = false)
    public CommonResult<String> network() {
        return success(loginProperties.getNetwork());
    }

    @PostMapping("/ilogincode")
    @ApiOperation("使用验证码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<SysAuthLoginRespVO> iloginCode(@RequestBody @Valid SysAuthLoginCodeReqVO reqVO) {
        SysUserDO user = userService.getUserByUsername(reqVO.getUsername());
        if (user == null) {
            return error("账号未登记");
        }
        if (StringUtils.isEmpty(user.getMobile())) {
            return error("账号未登记手机号码");
        }
        String token = authService.loginCode(reqVO, getClientIP(), getUserAgent());
        // 返回结果
        return success(SysAuthLoginRespVO.builder().token(token).build());
    }

    //验证码
    @PostMapping("/icode")
    @ApiOperation("获取短信/浙政钉验证码")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult identifyingCode(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
        SysUserDO user = userService.getUserByUsername(reqVO.getUsername());
        if (user == null) {
            return error("账号未登记");
        }
        if (StringUtils.isEmpty(user.getMobile())) {
            return error("账号未登记手机号码");
        }

        String code = "";
        for (int i = 0; i < 6; i++) {
            code += RandomUtils.nextInt(0, 10) + "";
        }
        // 缓存到 Redis 中
        captchaRedisDAO.set(code, code, captchaProperties.getTimeout());
        //todo 验证码短信+政务钉发送
//        SMSUtil.sendMessageByDb(user.getMobile(), "【数字扫黑】 验证码:" + code + ",为了确保系统登录安全，正在进行登录验证，5分钟内有效，请勿泄露");
        return success(null);
    }

    @GetMapping("/get-permission-info")
    @ApiOperation("获取登陆用户的权限信息")
    public CommonResult<SysAuthPermissionInfoRespVO> getPermissionInfo() {
        // 获得用户信息
        SysUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return null;
        }
        // 获得角色列表
        List<SysRoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
        // 获得菜单列表
        List<SysMenuDO> menuList = permissionService.getRoleMenusFromCache(
                getLoginUserRoleIds(), // 注意，基于登陆的角色，因为后续的权限判断也是基于它
                SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
                SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
        // 拼接结果返回
        return success(SysAuthConvert.INSTANCE.convert(user, roleList, menuList));
    }

    @GetMapping("list-menus")
    @ApiOperation("获得登陆用户的菜单列表")
    public CommonResult<List<SysAuthMenuRespVO>> getMenus() {
        // 获得用户拥有的菜单列表
        List<SysMenuDO> menuList = permissionService.getRoleMenusFromCache(
                getLoginUserRoleIds(), // 注意，基于登陆的角色，因为后续的权限判断也是基于它
                SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
                SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
        // 转换成 Tree 结构返回

        List<SysAuthMenuRespVO> menus = SysAuthConvert.INSTANCE.buildMenuTree(menuList);

        //外网(政务网仅保留这几个)
        String network = loginProperties.getNetwork();
        if (StrUtil.isNotBlank(network)){
            if (network.equals("out")){
                List<SysAuthMenuRespVO> newmenus = new ArrayList<>();
                for (SysAuthMenuRespVO menu:menus){
                    if (menu.getPath().equals("/system")
                            || menu.getPath().equals("/tool")
                            || menu.getPath().equals("/s3")){
                        if (menu.getPath().equals("/s3")){
                            List<SysAuthMenuRespVO> childrens = new ArrayList<>();
                            for (SysAuthMenuRespVO c:menu.getChildren()) {
                                if (c.getPath().equals("letter")
                                        || c.getPath().equals("practitioner")
                                        || c.getPath().equals("enterprise")
                                        || c.getPath().equals("list")) {
                                    childrens.add(c);
                                }
                            }
                            menu.setChildren(childrens);
                        }
                        newmenus.add(menu);
                    }
                }
                menus = newmenus;
            }
        }

        return success(menus);
    }

}
